/*
 * Project: Sudoku Explainer
 * Copyright (C) 2006-2007 Nicolas Juillerat
 * 
 * Project: Sudoku Hint Engine for Android
 * Copyright (C) 2010-2013 Emanuel Moecklin
 * 
 * Available under the terms of the Lesser General Public License (LGPL)
 */
package com.onegravity.sudoku.solver.rules.naked;

import java.util.BitSet;

import com.onegravity.sudoku.solver.HintResource;
import com.onegravity.sudoku.solver.R;
import com.onegravity.sudoku.solver.accumulator.HintsAccumulator;
import com.onegravity.sudoku.solver.accumulator.StopHintProductionException;
import com.onegravity.sudoku.solver.core.DirectHintProducer;
import com.onegravity.sudoku.solver.data.Cell;
import com.onegravity.sudoku.solver.data.Grid;
import com.onegravity.sudoku.solver.data.Region;
import com.onegravity.sudoku.solver.data.Row;
import com.onegravity.sudoku.solver.util.SudokuValidator;

/**
 * Implementation of the Naked Single solving techniques.
 */
public class NakedSingleProducer implements DirectHintProducer {

	private SudokuValidator validator;

	/**
     * Check if a cell has only one potential value, and accumulate
     * corresponding hints
	 * @throws InterruptedException 
     */
    public void getHints(Grid grid, HintsAccumulator accu) throws StopHintProductionException, InterruptedException {
    	getNakedSinglesCandidates(grid, accu);
    	getNakedSinglesNoCandidates(grid, accu);
    }

    /**
     * This method searches for naked singles based on pencil marks
     */
    private void getNakedSinglesCandidates(Grid grid, HintsAccumulator accu) throws StopHintProductionException, InterruptedException {
    	Region[] rows = grid.getRegions(Row.class);
        // iterate on rows
        for (Region row : rows) {
            if (Thread.interrupted()) throw new InterruptedException();
            // iterate on cells
            for (Cell cell:row.getCellSet()) {
                // Get the cell's potential values
                BitSet potentialValues = cell.getPotentialValues();
                if (potentialValues.cardinality() == 1) {
                    // only one potential value -> naked single found
                    int uniqueValue = potentialValues.nextSetBit(0);
                    NakedSingleHint hint = new NakedSingleHint(null, cell, uniqueValue, grid.findDigits(uniqueValue), grid.findPotentials(uniqueValue), true); 
                    accu.add( hint );
                }
            }
        }
    }

    /**
     * This method searches for naked singles without candidates
     */
    private void getNakedSinglesNoCandidates(Grid grid, HintsAccumulator accu) throws StopHintProductionException, InterruptedException {
		validator = new SudokuValidator(grid);
		for (int index=0; index<81; index++) {
			if (validator.isEmpty(index)) {
                BitSet potentialValues = validator.getCandidates(index);
                if (potentialValues.cardinality()==1) {
                    // only one potential value -> naked single found
                    Cell cell = grid.getCell(index);
                    int uniqueValue = potentialValues.nextSetBit(0);
                    NakedSingleHint hint = new NakedSingleHint(null, cell, uniqueValue, grid.findDigits(uniqueValue), grid.findPotentials(uniqueValue), false); 
                    accu.add( hint );
                }
			}
		}
    }

	@Override
	public String getProducerName() {
		return HintResource.getString(R.string.producer_naked_singles);
	}
}